#pragma once

#include <iostream>
#include <functional>
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
#include "Log.hpp"
#include <vector>
#include <queue>

namespace ThreadPoolModel
{

    using namespace LockMutex;
    using namespace LogModel;
    using namespace CondModule;
    using namespace ThreadMode;

    const static int num = 10;
    using thread_t = std::shared_ptr<mythread>;

    template <typename T>
    class ThreadPool
    {
    private:
        bool Emptr()
        {
            return _tack_queue.empty();
        }

        void HandlerTest()
        {
            LOG(LgoLevel::DEBUG) << "线程进入测试";
            while (true)
            {
                // 接收任务
                T t;
                {
                    LockGurd lockgurd(_lock);
                    while (Emptr() && _isrunning)
                    {
                        _waitnum++;
                        _cond.Wait(_lock);
                        _waitnum--;
                    }
                    if (Emptr() && !_isrunning)
                        break;

                    t = _tack_queue.front();
                    _tack_queue.pop();

                    // 执行任务
                    t(); // 默认每一个线程都有这个执行方法
                }
            }
        }

        // 禁用赋值和拷贝
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
        ThreadPool(const ThreadPool<T> &) = delete;

    public:
        static ThreadPool<T> *GetInstance()
        {
            LOG(LgoLevel::INFo) << "单例首次被执行，需要加载对象...";
            if (_instance == NULL)
                if (_instance == NULL)
                {
                    _instance = new ThreadPool<T>();
                }
            LockGurd lockguard(mutex);
            if (_instance == NULL)
            {
                LOG(LgoLevel::INFo) << "单例首次被执行，需要加载对象...";
                _instance = new ThreadPool<T>();
            }
            return _instance;
        }
        ThreadPool(int numbre = num) : _num(number), _waitnum(0), _isrunning(false)
        {
            for (int i = 0; i < num; i++)
            {
                _threads.push_back(std::make_shared<mythread>(std::bind(&ThreadPool::HandlerTest, this)));
                LOG(LgoLevel::INFo) << _threads.back()->Name() << "线程创建成功";
            }
        }
        void InitThreadPool()
        {
        }
        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true; // bug fix??
            for (auto &thread_ptr : _threads)
            {
                LOG(LgoLevel::INFo) << "启动线程" << thread_ptr->Name() << " ... 成功";
                thread_ptr->strat();
            }
        }
        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread->join();
                LOG(LgoLevel::INFo) << "线程退出";
            }
        }

        void Enqueue(T &&in)
        {
            LockGurd lockguard(_lock);
            if (!_isrunning)
                return;
            _tack_queue.push(std::move(in));
            if (_waitnum > 0)
                _cond.Notify();
        }

        void Stop()
        {
            LockGurd lockguard(_lock);
            if (_isrunning)
            {
                // 3. 不能在入任务了
                _isrunning = false; // 不工作
                // 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了
                if (_waitnum > 0)
                    _cond.NotifyAll();
            }
        }

        ~ThreadPool()
        {
        }

    private:
        int _num;
        std::vector<thread_t> _threads; // 线程池
        std::queue<T> _tack_queue;      // 任务
        mutex _lock;                    // 锁
        Cond _cond;
        int _waitnum;    // 等待的线程数
        bool _isrunning; // 判断线程的状态

        // 单例吗模式
        static ThreadPool<T> *_instance;
        static mutex _mutex;
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
    template <typename T>
    mutex ThreadPool<T>::_mutex;

}
